using System;
using System.IO;
using System.Collections.Generic;
using System.Text;

namespace MyMedia.iPod
{
	public abstract class Node
	{
		Node m_parent;
		List<Node> m_children;
		Database m_database;
		
		protected Node() : this(null) { }
		protected Node(Node parent)
		{
			m_parent = parent;
			m_children = new List<Node>();
		}

		internal Node Parent
		{
			get { return m_parent; }
			set { m_parent = value; }
		}

		internal virtual void AddChild(Node node)
		{
			node.Parent = this;
			m_children.Add(node);
		}

		internal virtual void RemoveChild(Node node)
		{
			node.Parent = this;
			m_children.Remove(node);
		}

		internal IList<Node> Children
		{
			get { return m_children; }
		}

		internal Database Database
		{
			get
			{
				if (m_database == null)
					m_database = m_parent.Database;

				return m_database;
			}
			set { m_database = value; }
		}

		internal T GetNode<T>() where T : Node
		{
			T t = default(T);
			FindNode<T>(Children, ref t);

			return t;
		}

		internal void Read(BinaryReader reader)
		{
			ReadImpl(reader);
		}

		internal void Write(BinaryWriter writer)
		{
			int size = GetTotalSize();
			SetSize(size);

			WriteImpl(writer);

			foreach (Node node in Children)
				node.Write(writer);
		}

		protected virtual int GetTotalSize()
		{
			int size = Size;
			foreach (Node child in Children)
				size += child.GetTotalSize();

			return size;
		}

		private void FindNode<T>(IList<Node> children, ref T node) where T : Node
		{
			if (node != default(T))
				return;

			foreach (Node child in children)
			{
				if (child is T)
				{
					node = (T)child;
					break;
				}
				else
					FindNode<T>(child.Children, ref node);
			}		
		}

		protected virtual int Size { get { return 0; } }

		protected abstract void SetSize(int size);
		protected abstract void ReadImpl(BinaryReader reader);
		protected virtual void WriteImpl(BinaryWriter writer) { }
	}
}
